package org.flashbrighton.as3bots.physics
{	
	import Box2D.Collision.Shapes.*;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.*;
	import flash.display.Sprite;
	import flash.geom.Point;
	
	
	public class Box2DWrapper
	{		
		// How much simulation time elapses between each call to step()
		private static const TIME_STEP:Number = 1.0 / 30.0;
		// How many times the collision detection code is run  with each call to step()
		private static const NUM_VELOCITY_ITERATIONS:int = 10;
		
		private static const NUM_POSITION_ITERATIONS:int = 10;
		// Initial gravity settings (0,0 for top-down)
		private static const GRAVITY_X:Number = 0;
		private static const GRAVITY_Y:Number = 0;
		
		private static const DRAW_SCALE:Number = 50.0;
		
		
		// The world controlling the physics simultion
		private var _world:b2World;
		
		// Dimensions of the simulation world
		private var _width:Number;
		private var _height:Number;
		
		
		public function Box2DWrapper(widthMetres:Number, heightMetres:Number) 
		{
			_width = widthMetres;
			_height = heightMetres;
			
			initWorld();
		}
		
		
		// Call this method to update the physics simulation.
		public function step():void 
		{
			_world.Step(TIME_STEP, NUM_VELOCITY_ITERATIONS, NUM_POSITION_ITERATIONS);
			_world.ClearForces();
		}
		
		
		public function get world():b2World 
		{
			return _world;
		}
		
		
		private function initWorld():void 
		{			
			_world = new b2World(new b2Vec2(GRAVITY_X, GRAVITY_Y), true);
		}
		
		
		public function addBox(cx:Number, cy:Number,	halfWidth:Number,	halfHeight:Number):b2Body 
		{
			var boxShape:b2PolygonShape = new b2PolygonShape();
			var boxDef:b2BodyDef = new b2BodyDef();
			var boxBody:b2Body;
			var fixtureDef:b2FixtureDef = new b2FixtureDef();
			
			fixtureDef.shape = boxShape;
			fixtureDef.density = 100.0;
			fixtureDef.friction = 0.3;
			fixtureDef.restitution = 0.2;
			
			boxDef.position.Set(cx, cy);
			boxDef.type = b2Body.b2_staticBody;
			boxShape.SetAsBox(halfWidth, halfHeight);
			boxBody = _world.CreateBody(boxDef);
			boxBody.CreateFixture(fixtureDef);
			
			return boxBody;
		}
		
		
		public function addCircle(cx:Number, cy:Number,	radius:Number, density:Number, friction:Number, restitution:Number):b2Body
		{
			var circleShape:b2CircleShape = new b2CircleShape(radius);
			var circleDef:b2BodyDef = new b2BodyDef();
			var circleBody:b2Body;
			var fixtureDef:b2FixtureDef = new b2FixtureDef();
			
			fixtureDef.shape = circleShape;
			fixtureDef.density = density;
			fixtureDef.friction = friction;
			fixtureDef.restitution = restitution;
			
			circleDef.position.Set(cx, cy);
			circleDef.type = b2Body.b2_dynamicBody;
			circleBody = _world.CreateBody(circleDef);
			circleBody.CreateFixture(fixtureDef);
			
			return circleBody;
		}
		
		
		public function addSensor():b2Body 
		{
			var boxShape:b2PolygonShape = new b2PolygonShape();
			var boxDef:b2BodyDef = new b2BodyDef();
			var boxBody:b2Body;
			var fixtureDef:b2FixtureDef = new b2FixtureDef();
			
			fixtureDef.shape = boxShape;
			fixtureDef.density = 0.0;
			fixtureDef.friction = 0.0;
			fixtureDef.restitution = 0.0;
			fixtureDef.isSensor = true;
			
			boxDef.position.Set(10, 12);
			boxDef.type = b2Body.b2_staticBody;
			boxShape.SetAsBox(1.0, 0.1);			
			boxBody = _world.CreateBody(boxDef);
			boxBody.CreateFixture(fixtureDef);
			
			return boxBody;
		}
		 
		 
		/******************************************************************************************
		* DEBUG WIREFRAME DRAWING
		******************************************************************************************/
		public function setDebugDraw(s:Sprite):void
		{
			var dbgDraw:b2DebugDraw = new b2DebugDraw();
			dbgDraw.SetSprite(s);
			dbgDraw.SetDrawScale(DRAW_SCALE);
			dbgDraw.SetFillAlpha(0.3);
			dbgDraw.SetLineThickness(1.0);
			dbgDraw.SetFlags(b2DebugDraw.e_shapeBit);
			_world.SetDebugDraw(dbgDraw);
		}
		
		
		public function drawWireframes():void 
		{
			_world.DrawDebugData();
		}
		
	}
}